Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

luhn: Update Luhn tests and description #474

Merged
merged 6 commits into from
Jan 11, 2017

Conversation

IanWhitney
Copy link
Contributor

I'm addressing a few different things here:

  1. The tests exposed functionality that is not needed

The addends and check_digit methods aren't needed by clients of this
code, and I didn't see that students got any benefit from explicitly
implementing them. The presence of these tests pushed students towards a
particular implementation, which we try to
avoid

The test cases should not require people to follow one very specific
way to solve the problem, e.g. the tests should avoid checking for
helper functions that might not be present in other implementations.

To fix this I've removed tests of addends and check_digit.

  1. The tests were duplicative.

There's not a way (that I could see, at least) of implementing Luhn in
tiny steps. It's either working or its not. Once you have a couple valid
tests and a couple invalid tests your are pretty much covered. (note: I
guess you could test the cases where Luhn can be wrong, but that seemed
outside the scope of this exercise.)

Again, from the guide

All tests should be essential to the problem. Ensure people can get
the first test passing easily. Then each following test should ideally
add a little functionality. People should be able to solve the problem a
little at a time. Avoid test cases that don't introduce any new aspect
and would already pass anyway.

To fix this I've removed most duplicative tests that would pass as soon
as the student got a working Luhn implementation.

  1. The examples and the description didn't match

Luhn can be hard to grasp. At least it can be for me. What helps me is
to have explicit, real-world examples. To help with this I've updated
the description.md file to have examples of credit cards and Canadian
SINs, two places where Luhn is used in the real world.

To re-enforce the descriptions, I've used the same examples in the
tests. So students can see step-by-step breakdowns of how to get their
tests passing.

Note:

I'm still on the fence about the generate_check_digit method. It seems
to be to be outside the scope of this exercise, but I also think
implementing it is interesting and useful. I could go either way on
keeping it or removing it.

Double the second digits, starting from the right

```
086 858 276
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the 7 in the final position has changed back to a 6 here.

```

Given an account number your code should be able to return a check digit
that can be appended to the account to generate a valid Luhn
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a valid Luhn

You will have to excuse a question from someone unfamiliar with the domain, but is it valid to use here "Luhn" as a shorthand for "number that is valid according to Luhn algorithm"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a bad sentence. I was hoping people wouldn't notice.

@Insti
Copy link
Contributor

Insti commented Dec 22, 2016

I like what you're doing here, and appreciate the detailed description in the OP. ❤️

I'm slightly against including the generate_check_digit tests, since it does force an implementation detail. This could be an opportunity to encourage the student to write their own tests for that function.

Some suggestions:

  • Move the check digit tests before the validation tests.
  • Rename generate_check_digit to check_digit
  • Include simple tests for the minimal case of 2+1 digit numbers.
  • What about tests for degenerate cases? 1 digit numbers?
  • Include test for 0?

@IanWhitney
Copy link
Contributor Author

I'm slightly against including the generate_check_digit tests, since it does force an implementation detail. This could be an opportunity to encourage the student to write their own tests for that function.

I'm not sure how this would look. Include the tests but mark them as optional? Or just say in the readme, "Maybe you want to write this function to generate a check digit."?

Include simple tests for the minimal case of 2+1 digit numbers.

Normally I would start off with tests of small inputs, and the old test suite had some tests that did this. But with this exercise the size of the input doesn't matter much. Small or long, the algorithm is exactly the same. So tests of short strings weren't any easier for students to implement.

What about tests for degenerate cases?

I'm not sure what a degenerate case would be here. There are strings that can pass validation even if certain numbers are transposed, but I didn't see much value in testing that here. I guess we could have a test of strings that contain non-digits.

1 digit numbers?
Include test for 0?

1 digit inputs should always be false. Makes sense to test that.

@Insti Insti changed the title Update Luhn tests and description luhn: Update Luhn tests and description Dec 29, 2016
@IanWhitney
Copy link
Contributor Author

I think I've addressed the concerns so far.

The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is
a simple checksum formula used to validate a variety of identification
numbers, such as credit card numbers and Canadian Social Insurance
Numbers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add a sentence or two describing what we're supposed to be doing.

"The task is to write a function to check if a given number is valid."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

I'm addressing a few different things here:

1. The tests exposed functionality that is not needed

The `addends` and `check_digit` methods aren't needed by clients of this
code, and I didn't see that students got any benefit from explicitly
implementing them. The presence of these tests pushed students towards a
particular implementation, which we [try to
avoid](https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md#improving-consistency-by-extracting-shared-test-data)

> The test cases should not require people to follow one very specific
way to solve the problem, e.g. the tests should avoid checking for
helper functions that might not be present in other implementations.

To fix this I've removed tests of `addends` and `check_digit`.

2. The tests were duplicative.

There's not a way (that I could see, at least) of implementing Luhn in
tiny steps. It's either working or its not. Once you have a couple valid
tests and a couple invalid tests your are pretty much covered. (note: I
guess you could test the cases where Luhn can be wrong, but that seemed
outside the scope of this exercise.)

Again, from the guide

> All tests should be essential to the problem. Ensure people can get
the first test passing easily. Then each following test should ideally
add a little functionality. People should be able to solve the problem a
little at a time. Avoid test cases that don't introduce any new aspect
and would already pass anyway.

To fix this I've removed most duplicative tests that would pass as soon
as the student got a working Luhn implementation.

3. The examples and the description didn't match

Luhn can be hard to grasp. At least it can be for me. What helps me is
to have explicit, real-world examples. To help with this I've updated
the description.md file to have examples of credit cards and Canadian
SINs, two places where Luhn is used in the real world.

To re-enforce the descriptions, I've used the same examples in the
tests. So students can see step-by-step breakdowns of how to get their
tests passing.

Note:

I'm still on the fence about the `generate_check_digit` method. It seems
to be to be outside the scope of this exercise, but I also think
implementing it is interesting and useful. I could go either way on
keeping it or removing it.
No one voiced a strong argument for keeping the Check Digit tests, so
I'm removing the test and their section in the description.

As recommended, I'm adding 3 tests

- invalid string containing a non-digit
- Single digit 0 (which can return 0 for `modulo 10`) is not valide
- Non-zero single digit is invalid
@Insti
Copy link
Contributor

Insti commented Jan 2, 2017

It concerns me that the entire test suite can be passed by:

return input == "046 454 286"

@IanWhitney
Copy link
Contributor Author

IanWhitney commented Jan 2, 2017 via email

@IanWhitney
Copy link
Contributor Author

Any more updates here? If not, I'll merge on Sunday, January 8.

@jtigger
Copy link
Contributor

jtigger commented Jan 23, 2017

(way late to the party...)

❤️ this! Thanks for tackling this, @IanWhitney. It was a less-than-delightful experience to go through this exercise as it was. 🙇

also...

@Insti said:

It concerns me that the entire test suite can be passed by...

@IanWhitney replied

We could add more positive cases...and the students could pass them with a switch statement.

To me this seems like a problem solved by the nitpickers.

Oh yeah, we've got tons of exercises where there are sufficiently few test cases that they can be "defeated" by pure conditional logic (aka "evil coder").

I'm assuming we're working with practitioners who understand you get what you put in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants